﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Logic;
using Logic.Models;
using Logic.ClarizenSvc;
using Logic.ClarizenObjects;
using BLL;

namespace ClarizenGadget.Controllers
{
    public class TasksController : Controller
    {
        [HttpPost]
        public ActionResult Details(String taskID)
        {
            try
            {
                var task = Task.GetTask(taskID);
                return Json(new GadgetResponse<Task> { Status = GadgetResponseStatus.Success, Data = task });
            }
            catch(Exception e)
            {
                return Json(new GadgetResponse<Task> { Status = GadgetResponseStatus.Error, ErrorMessage = e.Message }); 
            }
        }

        

        public ActionResult Index()
        {
            var config = ViewConfiguration.GetViewConfig();
            
            var queryApi = new QueryComponent();

            //var fields = queryApi.GetEntityDescription("Task").Fields.Where(f => BaseObject.GetFields<Task>().Contains(f.Name)).ToDictionary(a => a.Name, v=> v.Updateable);
            
            TaskCreateModel model = new TaskCreateModel
            {
                Phases = queryApi.GetListByTypeName("Phase", useCache: true),
                Importance = queryApi.GetListByTypeName("Importance", useCache: true),
                Statuses = queryApi.GetListByTypeName("TrackStatus", useCache: true),
                Pending = queryApi.GetListByTypeName("Pending", useCache: true),
                TaskTypes = queryApi.GetListByTypeName("TaskType", useCache: true),
                States = queryApi.GetListByTypeName("State", useCache: true),
                DocumentTypes = queryApi.GetListByTypeName("DocumentType", useCache: true),
                AuthorizedGoogle = Users.GetCurrentUser().IsGoogleAuthorized,
                //FieldsUpdateable = fields
            };

            return View(config.View, model);
        }
        [HttpPost]
        [ValidateInput(false)]
        public ActionResult List(String q = "", int pageNumber = 0, WorkItemState state = WorkItemState.Current, WorkItemFilter role = WorkItemFilter.IHaveAnyRole, string orderField = "Name", Boolean ascending = true)
        {
            try
            {
                Boolean hasMore;
                long count;

                var fields = new String[]
                {
                    "DueDate",
                    "Importance",
                    "Name",
                    "ParentProject.Name",
                    "TrackStatus",
                    "PercentCompleted",
                    "Parent.Name",
                };
                Exception err;

                
                var res = new QueryComponent().GetWorkItems(WorkItemType.Task, role, state, out hasMore, out count, out err, q
                    , PageNumber: pageNumber, returnCount: pageNumber == 0, fields: fields, fetchCount: 20, orderField: orderField, order: ascending ? Order.Ascending : Order.Descending);

                if(err != null)
                    return Json(new GadgetResponse<Object>
                    {
                        Status = GadgetResponseStatus.Error,
                        ErrorMessage = err.Message,
                        RedirectUrl = err.Message.ToLower().Contains("your session has expired") ? BLL.Users.GetAuthorizationLink() : ""
                    });

                return Json(new
                {
                    hasMore = hasMore,
                    count = count,
                    list = res.Select(r => new
                    {
                        r.DueDateString,
                        //r.Duration,
                        r.ID,
                        r.Importance,
                        //r.Manager,
                        r.Name,
                        r.Parent_Name,
                        r.ParentProject_Name,
                        r.PercentCompleted,
                        //r.RemainingEffort,
                        //r.Resources,
                        //r.StartDateString,
                        //r.State,
                        r.TrackStatus,
                        //r.Work
                    }),
                }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception e)
            {
                return Json(new GadgetResponse<Object> { 
                                    Status = GadgetResponseStatus.Error, 
                                    ErrorMessage = e.Message,
                                    RedirectUrl = e.Message.ToLower().Contains("your session has expired")? BLL.Users.GetAuthorizationLink():"" 
                });
            }
        }

        public ActionResult IndexLocal()
        {
            var entities = new QueryComponent().GetListByTypeName("Task", "", 10, BaseObject.GetFields(typeof(Task)), false).Cast<GenericEntity>();
            var queryApi = new QueryComponent();

            var res = queryApi.GetListByTypeName(new[] { "User", "State", "Phase", "Importance", "TrackStatus", "Pending" }.Select(t => new QueryComponent.ListQuery { Count = 20, Type = t }).ToList());
            TaskSideBarModel model = new TaskSideBarModel
            {
                TasksJson = entities.Select(e => new Task(e)).ToJson(),
                Lists = res.ToDictionary(r => r.Key, r => r.Value.Select(ge => (Object)new { Key = ge.Id.Value, Value = ge.Values[0].Value }))
            };

            return View("index", model);
        }

        public ActionResult Create()
        {
            var queryApi = new QueryComponent();

            var config = ViewConfiguration.GetViewConfig();
            // State
            var listNames = new[] { "User", "Phase", "Importance", "TrackStatus", "Pending", "TaskType", "State" };

            Dictionary<string, List<GenericEntity>> res = new Dictionary<string, List<GenericEntity>>();
            res = queryApi.GetListByTypeName(listNames.Select(t => new QueryComponent.ListQuery { Count = 20, Type = t }).ToList());
            TaskCreateModel model = new TaskCreateModel
            {
                Phases = queryApi.GetListByTypeName("Phase", useCache: true),
                Importance = queryApi.GetListByTypeName("Importance", useCache: true),
                Statuses = queryApi.GetListByTypeName("TrackStatus", useCache: true),
                Pending = queryApi.GetListByTypeName("Pending", useCache: true),
                TaskTypes = queryApi.GetListByTypeName("TaskType", useCache: true),
                States = queryApi.GetListByTypeName("State", useCache: true),
                DocumentTypes = queryApi.GetListByTypeName("DocumentType", useCache: true),
                AuthorizedGoogle = Users.GetCurrentUser().IsGoogleAuthorized
            };
            return View("Create_C", model);
        }


        // fix create view workItem, docID, email
        [HttpPost]
        [ValidateInput(false)]
        public ActionResult Create(Task task)
        {
            try
            {
                task.ID = new EntityId { Value = Guid.NewGuid().ToString(), TypeName = "Task" };
                var messages = new List<BaseMessage>();

                if (task.Documents != null && task.Documents.Count > 0)
                {
                    var links = task.Documents.Select(d => new GenericEntity
                    {
                        Id = new EntityId
                        {
                            TypeName = "AttachmentLink"
                        },
                        Values = new FieldValue[]{
                            new FieldValue{FieldName="WorkItem", Value = task.ID},
                            new FieldValue{FieldName="Document", Value = d.ID}
                        }
                    });
                    
                    messages.AddRange(links.Select(l=> new CreateMessage{Entity=l}));
                }

                if (task.Parent == null || task.Parent.Id == null || String.IsNullOrEmpty(task.Parent.Id.Value))
                {
                    EntityId id = Project.GetDefault();
                    task.Parent = new GenericEntity { Id = id };
                }

                var link = new GenericEntity
                {
                    Id = new EntityId { TypeName = "WorkItemHierarchyLink" },
                    Values = new FieldValue[]
                    {
                        new FieldValue{FieldName="Child", Value = task.ID},
                        new FieldValue{FieldName="Parent", Value = new EntityId{TypeName = "WorkItem", Value = task.Parent.Id.Value}}
                    }
                };
                messages.Add(new CreateMessage { Entity = link });
                

                if (task.Email != null && !string.IsNullOrEmpty(task.Email.Subject))
                {
                    var emailEntity = task.Email.ToGenericEntity();
                    var values = emailEntity.Values.ToList();
                    values.Add(new FieldValue { FieldName = "AttachedTo", Value = task});
                    emailEntity.Values = values.ToArray();

                    messages.Add(new CreateMessage { Entity = emailEntity });
                }
                messages.Insert(0, new CreateMessage { Entity = task.ToGenericEntity() });

                var res = new QueryComponent().Execute(messages.ToArray());

                return Json(new GadgetResponse<Task> { Data = task, Status = GadgetResponseStatus.Success });
            }
            catch (Exception e)
            {
                return Json(new GadgetResponse<Task> { Status = GadgetResponseStatus.Error, ErrorMessage = e.Message });
            }
        }

        [HttpPost]
        [ValidateInput(false)]
        public ActionResult Edit(Task t, List<String> added, List<string> deleted)
        {
            try
            {
                var qc = new QueryComponent();
                var task = t.ToGenericEntity();
                var values = task.Values.ToList();
                var fields = new List<string> { "StartDate", "DueDate", "Duration" };
                fields.AddRange(values.Select(v=>v.FieldName));
                var beforeSave = Task.GetTask(t.ID.Value, fields.ToArray());

                for (var i=0; i< values.Count; i++)
                {
                    var val = values[i];
                    if (!(beforeSave.Permissions.ContainsKey(val.FieldName) && beforeSave.Permissions[val.FieldName]))
                    {
                        values.Remove(val);
                        i--;
                    }
                }
                task.Values = values.ToArray();


                qc.UpdateEntity(task);


                var resourceUpdates = new List<BaseMessage>();
                if (added != null)
                {
                    var createMessages = added.Select(id => new CreateMessage
                    {
                        Entity = new GenericEntity
                        {
                            Id = new EntityId
                            {
                                TypeName = "ResourceLink"
                            },
                            Values = new FieldValue[]
                            {
                                new FieldValue {FieldName="Resource", Value = new EntityId{ TypeName="User", Value= id}},
                                new FieldValue {FieldName="WorkItem", Value = t.ID},
                            }
                        }
                    });
                    resourceUpdates.AddRange(createMessages);
                }

                if (deleted != null)
                {
                    var deleteMessages = deleted.Select(id => new DeleteMessage
                    {
                        Id = new EntityId
                        {
                            TypeName = "ResourceLink",
                            Value = id
                        }
                    });
                    resourceUpdates.AddRange(deleteMessages);
                }
                if(resourceUpdates.Count > 0)
                    qc.Execute(resourceUpdates.ToArray());

                var savedTask = Task.GetTask(t.ID.Value);
                if (!t.StartDate.HasValue)
                    t.StartDate = beforeSave.StartDate;
                if (!t.DueDate.HasValue)
                    t.DueDate = beforeSave.DueDate;
                if (t.Duration == null)
                    t.Duration = beforeSave.Duration;

                Boolean I_StartDate = !t.StartDate.HasValue || (savedTask.StartDate.HasValue && savedTask.StartDate.Value.Date == t.StartDate.Value.Date),
                        I_DueDate = !t.DueDate.HasValue || (savedTask.DueDate.HasValue && savedTask.DueDate.Value.Date == t.DueDate.Value.Date),
                        I_Duration = t.Duration == null || (savedTask.Duration != null && savedTask.Duration.ToString() == t.Duration.ToString());
                
                return Json(new GadgetResponse<Object>
                {
                    Status = GadgetResponseStatus.Success, Data = new { 
                    I_StartDate = I_StartDate,  
                    I_DueDate = I_DueDate, 
                    I_Duration = I_Duration,
                    task = savedTask
                }});
            }
            catch (Exception e)
            {
                return Json(new GadgetResponse<Task> { Status = GadgetResponseStatus.Error, ErrorMessage = e.Message });
            }
        }

        [HttpPost]
        public ActionResult CustomFields(String id)
        {
            var qc = new QueryComponent();
            
            EntityDescription ed = qc.GetEntityDescription("Task");
            var fields = ed.Fields.Where(f => f.Custom);

            if(string.IsNullOrEmpty(id))
                return Json(fields.Select(f => new {Name=f.Name, TypeName = f.TypeName, R_Type = f is EntityFieldDescription && ((EntityFieldDescription)f).ReferencedEntities.Length > 0? ((EntityFieldDescription)f).ReferencedEntities[0]: ""}));

            var qFields = fields.Select(f => f.Name).ToList();
            qFields.AddRange(fields.Where(f => f is EntityFieldDescription).Select(f => f.Name + ".Name"));

            var query = new RetrieveMessage
            {
                Fields = qFields.ToArray(), 
                Id = new EntityId{ TypeName="Task", Value=id},
                Permissions = PermissionOptions.ObjectAndFields,
                PermissionsSpecified = true 
            };

            var res = qc.Execute(new BaseMessage[] { query });
            if (res.Length > 0)
            {
                var entity = ((GenericEntity)((RetrieveResult)res[0]).Entity);
                var permissions = new Task(entity).Permissions;
                return Json(fields.Where(f => permissions.ContainsKey(f.Name)).Select(f => new
                {
                    Name=f.Name,
                    Label = f.Label,
                    TypeName = f.TypeName, 
                    R_Type = f is EntityFieldDescription && ((EntityFieldDescription)f).ReferencedEntities.Length > 0? ((EntityFieldDescription)f).ReferencedEntities[0]: "",
                    Value = entity.Values.FirstOrDefault(v => v.FieldName == f.Name).Value,
                    Disabled = !permissions[f.Name]
                }));
            }
            else return Json(null);
        }

        [HttpPost]
        public ActionResult SetState(string taskID, string state)
        {
            try
            {
                LifecycleMessage msg = new LifecycleMessage { Ids = new EntityId[]{new EntityId{TypeName = "Task", Value = taskID}}, Operation = state };
                var qc = new QueryComponent();
                qc.Execute(msg);

                return Json(new GadgetResponse<Boolean> { Data = true, Status = GadgetResponseStatus.Success });
            }
            catch (Exception e)
            {
                return Json(new GadgetResponse<Boolean> { Data = false, Status = GadgetResponseStatus.Error, ErrorMessage = e.Message });
            }
        }
    }
}
